#!/usr/bin/perl
#
# Copyright (c) 2020, 2022 NVI, Inc.
#
# This file is part of VLBI Field System
# (see http://github.com/nvi-inc/fs).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

# key to the functioning of this program is that edited out data
# is replaced with $$$, plotting puts out of range values on the top line
# all actual values are inside (not on) box
#
# if the log values are out of time order, i.e., time was reset back,
# plots may have odd appearances, but still reflect the log

sub nrml {
#
# normalize the pcal in $i-th channel by the tsys value that matches if any
#
    my($i,$chan)= @_;
    my($pv,$pt,$tv,$tt);
    my($ttref,$tvref,$ptref,$pvref);
    my($j,$min,$nfirst);
    $#pv=-1;
    $#pt=-1;
    $#tv=-1;
    $#tt=-1;
    for($j=0;$j<$pcaln[1][$i];$j++) {
	$pv[$j]=$pcala[1][$i][$j];
	$pt[$j]=$pcalt[1][$i][$j];
    }
    for($j=0;$j<$tsysn{$chan};$j++) {
	$tv[$j]=$tsysv{$chan}[$j];
	$tt[$j]=$tsyst{$chan}[$j];
    }
    ($ttref,$tvref,$ptref,$pvref)=match(\@tt,\@tv,\@pt,\@pv);
#
# find normalization value
#
    $min=1;
    $nfirst=0;
    for ($j=0;$j<=$#$ttref;$j++) {
	if((!($$tvref[$j]=~/^$float_pattern$/)) || 
	   (!($$pvref[$j]=~/^$float_pattern$/))) {
	    $$pvref[$j]='$$$';
	} else {
	    $$pvref[$j]=$$pvref[$j]*sqrt($$tvref[$j]);
	    if(!$nfirst && $$tvref[$j]>0) {
		$min=$$tvref[$j];
		$nfirst=1;
	    } else {
		$min=$$tvref[$j] if $$tvref[$j]<$min && $$tvref[$j]>0;
	    }
	}
    }
    $min = $opt_k if defined($opt_k);
#
# normalize, mark bad values
#	
    for ($j=0;$j<=$#$ttref;$j++) {
	if((!($$tvref[$j]=~/^$float_pattern$/)) || 
	   (!($$pvref[$j]=~/^$float_pattern$/))) {
	    $$pvref[$j]='$$$';
	} else {
	    $$pvref[$j]=$$pvref[$j]/sqrt($min);
	}
    }
#
# be sure to return the amp time, so times will match phase times for 'p' plots
#
    return($ptref,$pvref);
}

sub match {
#
# find nearest time match for two sets of values
# $time_dist sets the limit on successful matches
# each value can match only once
# 
# if the log values are out of time order, i.e., time was reset back,
# this will only find time values nearby in log, probably what you want
#
# bad values are preserved
#
    my ($t1,$v1,$t2,$v2) = @_;
    my ($ot1,$ov1,$ot2,$ov2);
    my ($dist,$dist1,$dist2,$n1,$n2,$on);
    $n2=0;
    $on=0;
    $#ot1=-1;
    $#ov1=-1;
    $#ot2=-1;
    $#ov2=-1;
  LOOP1:
    for ($n1=0;$n1<=$#$t1;$n1++) {
      while($n2<=$#$t2) {
	  $dist=abs($$t2[$n2] - $$t1[$n1]);
	  if($n1 < $#$t1) {
	      $dist1=abs($$t2[$n2] - $$t1[$n1+1]);
	      next LOOP1 if $dist1<$dist;
	  }
	  while($n2<$#$t2) {
	      $dist2=abs($$t2[$n2+1] - $$t1[$n1]);
	      last if $dist2 > $dist;
	      $n2++;
	      $dist=$dist2;
	  }
	  last;
      }
      if($n2 <= $#$t2) {
	  if($time_dist > ($$t2[$n2] - $$t1[$n1])) {
	      $ot1[$on]=$$t1[$n1];
	      $ov1[$on]=$$v1[$n1];
	      $ot2[$on]=$$t2[$n2];
	      $ov2[$on]=$$v2[$n2];
	      $on++;
	      $n2++;
	  }
      } else {
	  last;
      }
  }

    return (\@ot1,\@ov1,\@ot2,\@ov2);
}

sub phs {
#
# plot phase differences
#
    my ($i,$j)=@_;
    my ($tim1,$phs1,$tim2,$phs2);
    my ($tref1,$pref1,$tref2,$pref2,$k,$label);
    $#tim1=-1;
    $#phs1=-1;
    $#tim2=-1;
    $#phs2=-1;
    for($k=0; $k<$pcaln[1][$i];$k++) {
	$tim1[$k]=$pcalt[1][$i][$k];
	$phs1[$k]=$pcalp[1][$i][$k];
    }
    for($k=0; $k<$pcaln[1][$j];$k++) {
	$tim2[$k]=$pcalt[1][$j][$k];
	$phs2[$k]=$pcalp[1][$j][$k];
    }
    ($tref1,$pref1,$tref2,$pref2)=&match(\@tim1,\@phs1,\@tim2,\@phs2);

    for($k=0; $k<=$#$tref1;$k++) {
	if((!($$pref1[$k]=~/^$float_pattern$/)) || 
	   (!($$pref2[$k]=~/^$float_pattern$/))) {
	    $$pref1[$k]='$$$';
	} else {
	    $$pref1[$k]=$$pref2[$k]-$$pref1[$k];
	    if($$pref1[$k] > 180) {
		$$pref1[$k]-=360;
	    } elsif($$pref1[$k] < -180) {
		$$pref1[$k]+=360;
	    }
	}
    }
    &vu($tref1,$pref1,"Phase diff $pcall[1][$j]-$pcall[1][$i]");
}

sub vup {
#
# plot something versus phase, fixed -180->+180 x axis
#
    my($x,$y, $label) = @_;
    &vuy($x,$y,$label,2);
}

sub vu {
#
# regular y value versus time plot
#
    my($x,$y, $label) = @_;
    &vuy($x,$y,$label,1);
}
sub vuy {
#
# main plot function, see vuX functions above for options
#
    my($x,$y, $label, $type) = @_;
    my ($i,$ymax,$ymin,$ply,$nfirst,$xmax,$xmin,$plx);

    if(defined($opt_g)) {
	return if $label !~/$opt_g/i;
    }
    if(defined($opt_e)) {
	return if $label =~/$opt_e/i;
    }
    $ymax=0;
    $ymin=0;
    $nfirst=0;
    for($i=0;$i<=$#$y;$i++) {
	next unless $$y[$i]=~/^$float_pattern$/ ;
	if(!$nfirst) {
	    $ymax=$$y[$i];
	    $ymin=$$y[$i];
	    $nfirst=1;
	} else {
	    $ymax=$$y[$i] if $$y[$i]>$ymax;
	    $ymin=$$y[$i] if $$y[$i]<$ymin;
	}
    }

    if($type == 2) {
	$xmax=0;
	$xmin=0;
	$nfirst=0;
	for($i=0;$i<=$#$x;$i++) {
	    next unless $$x[$i]=~/^$float_pattern$/ ;
	    if(!$nfirst) {
		$xmax=$$x[$i];
		$xmin=$$x[$i];
		$nfirst=1;
	    } else {
		$xmax=$$x[$i] if $$x[$i]>$xmax;
		$xmin=$$x[$i] if $$x[$i]<$xmin;
	    }
	}
	$xmin=-180.;
	$xmax=+180.;
    }

    if(!$first && $panel==0) {
#	print "labeling X axis\n";
	if($type == 1) {
	    pgtbox("BCTNZYH",0.0,0,"BCNVT",0.0,0); 
	    pglabel("Time","","");
	} elsif($type == 2) {
	    pgbox("BCTN",0.0,0,"BCNVT",0.0,0); 
	    pglabel("Phase","","");
	}
	pgask(-1);
	pgpanl(1,8);
	pgpage();
    }
    if($panel==0) {
	pgpanl(1,1);
	pgvport(0.15,.95,0,1);
	pgwindow(-0.5,16.5,0,39);
	pgtext(4,10,"$location Log Plots -- $refdate $save_file Page $page");
	$first=0;
        $page++;
    }

#    print "panel $panel\n";
    pgpanl(1,2+$panel);
    pgvport(0.15,.95,0,1);
#
# handle pathologies: all y == 0 and just one y value
#
    if($ymin == 0 && $ymax == 0) {
	$ymax = 0.001;
	$ymin =-0.001;
    } elsif($ymin == $ymax) {
	$ymax=$ymax*1.001;
	$ymin=$ymin*0.999;
        if($ymax < $ymin) {
          ($ymax,$ymin)=($ymin,$ymax);
        }
    }
#
# put edited out values at the top
#
    for($i=0;$i<=$#$y;$i++) {
#	print "$$y[$i] ";
	if($$y[$i] =~/^$float_pattern$/) {
#	    print" matched ";
	    $ply[$i]=$$y[$i];
	} else {
#	    print" not matched ";
	    $ply[$i]=$ymax+0.05*($ymax-$ymin);
	}
#	print " ply $ply[$i]\n";
    }
    if($type == 2) {
#
# handle pathologies: x == 0 and just one x value
#
	if($xmin == 0 && $xmax == 0) {
	    $xmax = 0.001;
	    $xmin =-0.001;
	} elsif($xmin == $xmax) {
	    $xmax=$xmax*1.001;
	    $xmin=$xmin*0.999;
	    if($xmax < $xmin) {
		($xmax,$xmin)=($xmin,$xmax);
	    }
	}
#
# put bad values on right edge
#
	for($i=0;$i<=$#$x;$i++) {
#	print "$$x[$i] ";
	    if($$x[$i] =~/^$float_pattern$/) {
#	    print" matched ";
		$plx[$i]=$$x[$i];
	    } else {
#	    print" not matched ";
		$plx[$i]=$xmax+0.01*($xmax-$xmin);
	    }
#	print " plx $plx[$i]\n";
	}
    }

    if($type == 1 ){
	pgswin($tmin-0.01*($tmax-$tmin),$tmax+0.01*($tmax-$tmin),
	       $ymin-0.05*($ymax-$ymin),$ymax+0.05*($ymax-$ymin));
	pgtbox("BCTZYH",0.0,0,"BCNVT",0.0,0);
	pgpoint($#$y+1, $x,\@ply,17);
#    pgline($#$y+1, $x, $ply);
    } else {
	pgswin($xmin-0.01*($xmax-$xmin),$xmax+0.01*($xmax-$xmin),
	       $ymin-0.05*($ymax-$ymin),$ymax+0.05*($ymax-$ymin));
	pgbox("BCT",45.0,0,"BCNVT",0.0,0);
	pgpoint($#$y+1, \@plx,\@ply,17);
    }
    pgvport(0.075,.95,0,1);
    pglabel("",$label,"");
    pgvport(0.15,.95,0,1);
    $panel=(++$panel)%6;
}

sub time {
#
# calculate time of the log entry
# everything is measured relative to $reftime, first time in log
# it will make a mess of $reftime is not reasonable
#
    local ($date) = @_;
#2005.123.12:23:56.21
#01234567890123456789
#or
#9823717225512
#0123456789012
    if(substr($date,4,1) eq '.') {
	$year=substr($date,0,4);
	$day=substr($date,5,3);
	$hour=substr($date,9,2);
	$minute=substr($date,12,2);
	$second=substr($date,15,5);
    } else {
	$year=substr($date,0,2)+1900;
	$day=substr($date,2,3);
	$hour=substr($date,5,2);
	$minute=substr($date,7,2);
	$second=substr($date,9,4)/100;
    }
    if(!defined($refdate)) {
#	$refdate=substr($date,0,17);
	$refdate=sprintf "%04d.%03d.%02d:%02d:%05.2f",
	    $year,$day,$hour,$minute,$second;
	$refyear=$year;
	$refday=$day;
	$refhour=$hour;
	$refminute=$minute;
	$refsecond=$second;
#		print "$refyear $refday $refhour $refminute $refsecond\n";
	$tmax=0;
	$tmin=3e7;
    }
    $days_in_year=365;
    $days_in_year=366 if $refyear%4==0;
    $time=(((($year-$refyear)*$days_in_year
	     +$day-$refday)*24.0
	    +$hour-$refhour)*60.0
	   +$minute-$refminute)*60.0
	   +$second-$refsecond;
#	    print "$day $hour $minute $second $time\n";
    $tmax=$time if $time>$tmax;
    $tmin=$time if $time<$tmin;
    return $time;
}
#
# main program
#

# 1.0 Initialize

use PGPLOT;
require "getopts.pl";

&Getopts("12:abc:e:g:jk:rnps:t:u:wz:f:hv");

$float_pattern = '([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?';
@hex =("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f");

if ($#ARGV < 0 &&!defined($opt_h) &&!defined($opt_v)) {
    print STDERR "Try: 'plotlog -h'\n";
    exit 0;
}

if(defined($opt_v)) {
    print "[plotlog 1.8]\n";
    pgqinf("VERSION",$val,$len);
    print "using PGPLOT module version $PGPLOT::VERSION, PGPLOT $val library\n";
    exit 0;
}

if (defined($opt_h)) {
    print "Usage:\n";
    print "   plotlog [options] logs\n";
    print "Synopsis: extracts and plots data from log files\n";
    print "Exit code is 0 for no error, -1 for no logs found, -2 for nothing to plot.\n\n";

    print "This script finds wx/, cable/, tsys/ rx/ (or sk/ or sx/), gps-fmout/ (or\n";
    print "fmout-gps/), setcl#time/, and the first encountered USB tone per channel for\n";
    print "Mark IV decoder pcal data in log files and generates time plots of the data.\n";
    print "The time axis of all the plots is the same. The data is plotted so that it fits\n";
    print "entirely inside the boxes. Points that appear along the top line of a plot did\n";
    print "not decode (\$\$\$ for example) or were edited out by command line options.\n\n";

    print "The '1anw' switches can be used to select different IF arrangements for\n";
    print "calculating phase differences between pcal tones. Any combination of the '1anw'\n";
    print "switches can be used. No difference is plotted more than once.\n\n";

    print "The 'j' switch can be used to normalize pcal amplitudes by Tsys (per channel)\n";
    print "for time plots and amplitude versus phase plots. The minimum non-zero Tsys\n";
    print "(per channel) is used as the reference value for normalization. If this causes\n";
    print "problems, an explict global reference value can be specified with the 'k'\n";
    print "option. The 't' option may also be useful for removing bad Tsys values. By\n";
    print "default dual side-band Tsys is used for normalization if it is available, if\n";
    print "not then single side-band Tsys data is used. This is usually what is wanted\n";
    print "but if not, the 'b' option can be used to force use of single side-band Tsys\n";
    print "for channels that it is available for.\n\n";

    print "For the 'j1anw' switches a simple model is used to match different data from\n";
    print "the log. Points from different data types that are the nearest together in time\n";
    print "are matched. No epoch from one data type is matched to more than one epoch of\n";
    print "another type in this way. If the resulting matched epochs are within 60 seconds\n";
    print "of each other, the match is accepted. The tolerance of match can be adjusted\n";
    print "using the 'u' option.\n\n";

    print "The 'p' switch adds amplitude versus phase plots for each phase-cal tone after\n";
    print "all other plots. This option suppresses all other output except options -1anw.\n\n";
    print "Cable delay is plotted as one-way cable delay change unless the 'r' switch is\n";
    print "used.\n\n";

    print "fmout-gps and gps-fmput data are plotted as fmout-gps, flipping the sign of\n";
    print "any gps-fmout data.\n\n";

    print "Option explanations:\n";

    print " phase-difference plot options (suppresses all other output, except -p):\n";
    print "  -1 all converters are on one IF\n";
    print "  -a odd converters are on one IF, even are on another (astronomy)\n";
    print "  -n converters 1-8 on one band, 9-16 on a second (narrow band geodesy),\n";
    print "     also useful for wide band geodesy\n";
    print "  -w converters 1-4 on one band, 5-8 on a second, 9-16 on a third\n";
    print "     (wide band geodesy)\n\n";

    print " -b        force single-side-band Tsys normalization of pcal amp data\n";
    print " -c value  cable cal edit, if greater than zero, delete points that much or\n";
    print "           more above lowest value, if less than zero, delete points that much\n";
    print "           or more below largest value; uses plot Y axis units, be careful of\n";
    print "           the -r option\n";
    print " -e regexp include only plots with labels that DO NOT match 'regexp', where\n";
    print "           'regexp' is any Perl regular expression pattern, you will need to\n";
    print "           quote 'regexp' if it contains special characters, e.g., 'Temp|Hum'\n";
    print "           or spaces, this option can be combined with the 'g' option as well.\n";
    print "           The match is case insensitive.\n";
    print " -g regexp include only plots with labels that DO match 'regexp', where\n";
    print "           'regexp' is any Perl regular expression pattern, you will need to\n";
    print "           quote 'regexp' if it contains special characters, e.g., 'Temp|Hum'\n";
    print "           or spaces, this option can be combined with the 'e' option as well.\n";
    print "           The match is case insensitive.\n";
    print " -j        normalize phase-cal amp by Tsys per channel\n";
    print " -k value  changes 'j' normalization from minimum non-zero Tsys per channel to\n";
    print "           'value' for all channels\n";
    print " -p        plot amplitude versus phase for phase cal tones,\n";
    print "           suppresses all other output except -1anw\n";
    print " -r        plot cable data in raw units\n";
    print " -s string match commands with 'string' instead of 'tsys',\n";
    print "           option -t still applies for editing\n";
    print " -2 n      n is 1 or 2, useful for selecting which values to plot for\n";
    print "           -s tpicd#tpcont; 1 for first value, 2 for second\n";
    print " -t value  edit out tsys points less than or equal to zero or greater than or\n";
    print "           equal to 'value'\n";
    print " -z value  edit out pcal data with amplitudes less than 'value'\n";
    print " -u value  maximum distance in time (seconds) allowed for matching data for\n";
    print "           '1anwp' option plots is changed to 'value' instead of 60 seconds\n";
    print " -v        print program and PGPLOT version information and stop\n";
    print " -h        print this help information and stop\n";
    print " -f file/device  send graphs to 'file' using PGPLOT 'device'\n";
    print "    if -f omitted and DISPLAY is defined, '/xw' will be used\n";
    print "    if -f omitted and DISPLAY is not defined, 'plotlog.ps/vps' will be used\n";
    print "    if '-f ?', you will be prompted for standard pgplot devices,\n";
    print "               be sure to quote '?', like \\?\n";
    print "    'vps' (portrait PostScript) is a useful choice for 'device' for file output\n";
    print "    '.ps' works well as the file extension for device 'vps'\n\n";

    print "You can use different colors by setting the environment variables\n";
    print "PGPLOT_FOREGROUND and PGPLOT_BACKGROUND appropriately before running the\n";
    print "program. Colors that are available depend on the device, but in addition to\n";
    print "'black' and 'white', may include 'red', 'green', 'blue', 'cyan', 'magenta',\n";
    print "'yellow', 'grey', 'slategrey', 'gold', and maybe others.\n";
    exit 0;
}

if(defined($ENV{'DISPLAY'}) && !defined($opt_f)) {
    $dev="/xw";
} elsif(!defined($opt_f)) {
    $dev="plotlog.ps/vps";
} else {
    $dev=$opt_f;
}

$string="tsys";
$string = $opt_s if defined($opt_s);

$time_dist=60;
$time_dist = $opt_u if defined($opt_u);

# 2.0 extract data

$some=0;
$first=1;
$wxcount=0;
foreach $file (@ARGV) {
    if(!defined($save_file)) {
	$save_file=$file;
    }
    open(FILE,$file) || do {
	print STDERR "can't open $file: $!\n";
	next;
    };
    $some=1;
#   print "file $file \n";
    $x=0;
    $y=0;
    while (<FILE>) {
	chomp;
	if(/;location,([^,]*)/i) {
	    $location=$1;
	    (undef)=&time($_);
	}

	if(/wx\/[ ]*([^,]*),[ ]*([^,]*),[ ]*([^, \cM]*)/i) {
	    $temp[$wxcount]=$1;
	    $pres[$wxcount]=$2;
	    $humid[$wxcount]=$3;
	    $wxtime[$wxcount]=&time($_);
	    $wxcount++;
	} elsif(/cable\/[ ]*([^, \cM]*)/i) {
	    $cable[$cablen]=$1;
	    $cablet[$cablen]=&time($_);
	    $cablen++;
	} elsif(/pcalports[=\/]([^,]*),([0-9]+)/i||/vsi4[=\/][^,]*,([^,]*),([0-9]+)/i) {
	    $x=$1;
	    $y=$2;
#	    print "pcalports $1 $2\n";
	} elsif (/decode4\/[p]*cal ([lu])sb([xy])/i &&defined($x)) {
	    $sb = $1;
	    $port=$2;
#	    print "sb $sb port $2\n";
	    if($sb eq "u") {
		$band=1;
	    } elsif($sb eq "l") {
		$band=0;
	    } else {
		die "unknown side-band $sb\n";
	    }
	    if($port eq "x") {
		$chan=$x;
	    } elsif ($port eq "y") {
		$chan=$y;
	    } else {
		die "unknown pcal port $port\n";
	    }
	    (undef,undef,@fields)=split('[ \cM]');
	    next if($#fields!=3);
	    $freq=shift(@fields);
	    $rate=shift(@fields);
	    $amp=shift(@fields);
	    $phase=shift(@fields);
	    if(!defined($pcalf[$band][$chan])) {
		$pcalf[$band][$chan]=$freq;
	    } elsif($pcalf[$band][$chan]!=$freq) {
		next;
	    }
	    if(defined($opt_z) && $amp < $opt_z) {
		$amp='$$$';
		$phase='$$$';
	    }
	    $pcalt[$band][$chan][$pcaln[$band][$chan]]=&time($_);
	    $pcala[$band][$chan][$pcaln[$band][$chan]]=$amp;
	    $pcalp[$band][$chan][$pcaln[$band][$chan]]=$phase;
	    if($chan > -1 && $chan < 16 && !defined($pcall[$band][$chan])) {
		$pcall[$band][$chan]="$hex[$chan]$sb";
	    }
	    $pcaln[$band][$chan]++;
	} elsif (/pcaldisp2\/k5ts/i) {
	    (undef,undef,@fields)=split('[ /\cM]+');
	    $rec=substr($fields[0],-1);
            $ch=substr($fields[1],-1);
	    $chan = 4*($rec-1)+$ch;
            if(substr($fields[3],-3) ne "bit") {
		$fields[3] =~ s/hz//i;
		$freq = $fields[3];
		$iof=1;
	    } else {
		$freq = 10000;
		$iof=0;
	    }
	    $sb=substr($fields[4+$iof],0,1);
	    $amp=$fields[5+$iof];
	    $phase=$fields[6+$iof];
#	    print "chan $chan freq $freq sb $sb amp $amp phase $phase\n";
#	    print "sb $sb port $2\n";
	    if($sb eq "u") {
		$band=1;
	    } elsif($sb eq "l") {
		$band=0;
	    } else {
		die "unknown side-band $sb\n";
	    }
	    if(!defined($pcalf[$band][$chan])) {
		$pcalf[$band][$chan]=$freq;
	    } elsif($pcalf[$band][$chan]!=$freq) {
		next;
	    }
	    if(defined($opt_z) && $amp < $opt_z) {
		$amp='$$$';
		$phase='$$$';
	    }
	    $pcalt[$band][$chan][$pcaln[$band][$chan]]=&time($_);
	    $pcala[$band][$chan][$pcaln[$band][$chan]]=$amp;
	    $pcalp[$band][$chan][$pcaln[$band][$chan]]=$phase;
	    $pcall[$band][$chan]="$chan$sb";
	    $pcaln[$band][$chan]++;
	} elsif (/[#\/]$string\/(.*)/i) {
	    @fields=split('[,\cM]',$1);
	    while($detect=shift(@fields)) {
		$tsys=shift(@fields);
		if(defined($opt_2)) {
		    if($opt_2 == 1) {
			$detect="$detect (1)";
			shift(@fields);
		    } elsif(@fields) {
			$detect="$detect (2)";
			$tsys=shift(@fields);
		    } else {
			next;
		    }
		}
#		print "$detect $tsys\n";
		if(defined($opt_t)) {
		    $tsys= '$$$' if $tsys <= 0;
                    $tsys= '$$$' if $tsys >= $opt_t;
		}
		$tsysv{$detect}[$tsysn{$detect}]=$tsys;
		$tsyst{$detect}[$tsysn{$detect}]=&time($_);
#		print "tsys $tsysv{$detect}[$tsysn{$detect}]\n" if($detect eq '1u');
		$tsysn{$detect}++;	 
	    }
	} elsif (/\/tsys1=/i) {
	    (undef,undef,@fields)=split('[/=,\cM]');
	    $det=0;
	    while($device=shift(@fields)) {
		$det++;
#		print "$det $device\n";
		$tsys1{$det}=sprintf "%3s", $device;
	    }
	} elsif (/\/tsys1\//i) {
	    (undef,undef,@fields)=split('[/,\cM]');
	    $det=0;
	    while($tsys=shift(@fields)) {
		$det++;
		$detect=$tsys1{$det};
#		print "$detect $tsys\n";
		if(defined($opt_t)) {
		    $tsys= '$$$' if $tsys <= 0;
                    $tsys= '$$$' if $tsys >= $opt_t;
		}
		$tsysv1{$detect}[$tsysn1{$detect}]=$tsys;
		$tsyst1{$detect}[$tsysn1{$detect}]=&time($_);
#		print "tsys $tsysv1{$detect}[$tsysn1{$detect}]\n" if($det ==1);
		$tsysn1{$detect}++;	 
	    }
	} elsif (/\/tsys2=/i) {
	    (undef,undef,@fields)=split('[/=,\cM]');
	    $det=0;
	    while($device=shift(@fields)) {
		$det++;
#		print "$det $device\n";
		$tsys2{$det}=sprintf "%3s", $device;
	    }
	} elsif (/\/tsys2\//i) {
	    (undef,undef,@fields)=split('[/,\cM]');
	    $det=0;
	    while($tsys=shift(@fields)) {
		$det++;
		$detect=$tsys2{$det};
#		print "$detect $tsys\n";
		if(defined($opt_t)) {
		    $tsys= '$$$' if $tsys <= 0;
                    $tsys= '$$$' if $tsys >= $opt_t;
		}
		$tsysv2{$detect}[$tsysn2{$detect}]=$tsys;
		$tsyst2{$detect}[$tsysn2{$detect}]=&time($_);
#		print "tsys $tsysv2{$detect}[$tsysn2{$detect}]\n" if($det ==1);
		$tsysn2{$detect}++;	 
	    }
	} elsif (/\/tsys3=/i) {
	    (undef,undef,@fields)=split('[/=,\cM]');
	    $det=0;
	    while($device=shift(@fields)) {
		$det++;
#		print "$det $device\n";
		$tsys3{$det}=sprintf "%3s", $device;
	    }
	} elsif (/\/tsys3\//i) {
	    (undef,undef,@fields)=split('[/,\cM]');
	    $det=0;
	    while($tsys=shift(@fields)) {
		$det++;
		$detect=$tsys3{$det};
#		print "$detect $tsys\n";
		if(defined($opt_t)) {
		    $tsys= '$$$' if $tsys <= 0;
                    $tsys= '$$$' if $tsys >= $opt_t;
		}
		$tsysv3{$detect}[$tsysn3{$detect}]=$tsys;
		$tsyst3{$detect}[$tsysn3{$detect}]=&time($_);
#		print "tsys $tsysv3{$detect}[$tsysn3{$detect}]\n" if($det == 1);
		$tsysn3{$detect}++;	 
	    }
	} elsif (/\/(sx|rx|sk)\//i) {
            (undef,$cmd,@fields)=split('[/,\cM]');
            ($value,$units)=split(' ',$fields[$#fields]);
	    next unless $value=~/^$float_pattern$/ ;
	    ($rx{$fields[0]}[$rxcount{$fields[0]}],undef)=$value;
	    $rxtime{$fields[0]}[$rxcount{$fields[0]}]=&time($_);
#            print "$fields[0] $rx{$fields[0]}[$rxcount{$fields[0]}]\n";
            $rxcount{$fields[0]}++;
	    $rxunits{$fields[0]}=$units;
	    $rxcmd=$cmd;
	} elsif(/#setcl#time\//i) {
		(undef,@fields)=split('[/,\cM]');
		$setcl[$setcln]=$fields[9];
		$setclt[$setcln]=&time($_);
		$setcln++;
	} elsif(/\/((gps-fmout)|(fmout-gps))\//i) {
            (undef,$cmd,@fields)=split('[/,\cM]');
            if($fields[0] =~ /($float_pattern)/) {
		if($cmd eq "fmout-gps") {
		    $gpsv[$gpsn]=$1;
		} else {
		    $gpsv[$gpsn]=-$1;
		}
	    } else {
		$gpsv[$gpsn]=$fields[0];
	    }
            $gpst[$gpsn]=&time($_);
	    $gpsn++;
	}
    }
}
exit -1 if(!$some);

pgbegin(0,$dev,1,8);
pgsch(3);
pgask(-1);
pgpanl(1,8);
pgpage();

$page=1;
$panel=0;
$first=1;

goto EXTRAS
    if defined($opt_1)||defined($opt_a)||defined($opt_n)||defined($opt_w)||defined($opt_p);

if(@wxtime) {
    &vu(\@wxtime, \@temp,"Temperature");
    &vu(\@wxtime, \@pres,"Pressure");
    &vu(\@wxtime, \@humid,"Humidity");
}

if(@cablet) {
    if(!defined($opt_r)) {
        for($i=0;$i<=$#cable;$i++) {
	    next unless $cable[$i]=~/^$float_pattern$/ ;
            $cablefirst=$cable[$i] if(!defined($cablefirst));
            $cable[$i]=($cable[$i]-$cablefirst)/4e5;
            $cable[$i]/=1e-12;
	}
	if(defined($opt_c)) {
	    for($i=0;$i<=$#cable;$i++) {
		next unless $cable[$i]=~/^$float_pattern$/ ;
		$cablemax=$cable[$i] if(!defined($cablemax));
		$cablemin=$cable[$i] if(!defined($cablemin));
		if($cablemax <$cable[$i]) {
		    $cablemax=$cable[$i];
		} elsif($cablemin > $cable[$i]) {
		    $cablemin=$cable[$i];
		}
	    }
#	    printf "$cablemax $cablemin $opt_c\n";
	    for($i=0;$i<=$#cable;$i++) {
		next unless $cable[$i]=~/^$float_pattern$/ ;
		if($opt_c < 0 && $cable[$i] < $cablemax+$opt_c) {
		    $cable[$i]='$$$';
                } elsif($opt_c >0 && $cable[$i] > $cablemin+$opt_c) {
		    $cable[$i]='$$$';
                }
	    }
	}
	&vu(\@cablet, \@cable,"Cable Delay (ps)");
    } else {
        for($i=0;$i<=$#cable;$i++) {
	    next unless $cable[$i]=~/^$float_pattern$/ ;
            $cable[$i]*=1e3;
	}
	if(defined($opt_c)) {
	    for($i=0;$i<=$#cable;$i++) {
		next unless $cable[$i]=~/^$float_pattern$/ ;
		$cablemax=$cable[$i] if(!defined($cablemax));
		$cablemin=$cable[$i] if(!defined($cablemin));
		if($cablemax <$cable[$i]) {
		    $cablemax=$cable[$i];
		} elsif($cablemin > $cable[$i]) {
		    $cablemin=$cable[$i];
		}
	    }
#	    printf "$cablemax $cablemin $opt_c\n";
	    for($i=0;$i<=$#cable;$i++) {
		next unless $cable[$i]=~/^$float_pattern$/ ;
		if($opt_c < 0 && $cable[$i] < $cablemax+$opt_c) {
		    $cable[$i]='$$$';
                } elsif($opt_c >0 && $cable[$i] > $cablemin+$opt_c) {
		    $cable[$i]='$$$';
                }
	    }
	}
        &vu(\@cablet, \@cable,"Cable Counter (ms)");
    }
}
if(@gpst) {
    $avg=0;
    $count=0;
    for($i=0;$i<$gpsn;$i++) {
	next unless $gpsv[$i]=~/^$float_pattern$/ ;
	$gpsv[$i]*=1e6;  #microseconds
	$avg+=$gpsv[$i];
	$count++;
    }
#
# it seems PGPLOT can't handle lots of significant digits
#
#    print "$avg $count\n";
    $avg=$avg/$count;
#    print "$avg $count\n";
    if($avg > 500000) {
	$offset=1e6;
	$label="(fmout-gps)-1e6 (us)";
    } elsif($avg <-500000) {
	$offset=-1e6;
	$label="(fmout-gps)+1e6 (us)";
    } else {
	$offset=0;
	$label="fmout-gps (us)";
    }
#    print "$offset $label\n";
    if($offset) {
#	print "apply offset $offset\n";
	for($i=0;$i<$gpsn;$i++) {
	    next unless $gpsv[$i]=~/^$float_pattern$/ ;
	    $gpsv[$i]-=$offset;
	}
    }
    &vu(\@gpst, \@gpsv,$label);
}
if(@setcl) {
     &vu(\@setclt, \@setcl,"setcl offset (0.01 s)");
}
for($i=1;$i<17;$i++) {
    if(defined($pcaln[1][$i])) {
	$#amp=-1;
	$#tim=-1;
	$#phs=-1;
	for($j=0;$j<$pcaln[1][$i];$j++) {
	    $amp[$j]=$pcala[1][$i][$j];
	    $tim[$j]=$pcalt[1][$i][$j];
		$phs[$j]=$pcalp[1][$i][$j];
	}
#
# fix up to use dual sideband tsys for normalization, BUT specific sideband data
# if dual doesn't exist
#
	$chan=$pcall[1][$i];
	if(!defined($opt_b)) {
	    substr($chan,-1)="d";
	    $chan=$pcall[1][$i] if !defined($tsysn{$chan});
	}

	if(!defined($opt_j)) {		    
	    &vu(\@tim,\@amp,"$pcalf[1][$i] Hz Amp $pcall[1][$i]");
	} elsif(defined($tsysn{$chan})) {
	    ($ptref,$pvref)= &nrml($i, $chan);
	    &vu($ptref,$pvref,"$pcalf[1][$i] Hz Amp(Ts) $pcall[1][$i]");
	}
	&vu(\@tim,\@phs,"$pcalf[1][$i] Hz Phase $pcall[1][$i]");
    }
}

foreach $detect (sort keys %tsysn) {
#    print "Detect $detect $tsysn{$detect}\n";
    $#amp=-1;
    $#tim=-1;
    for($j=0;$j<$tsysn{$detect};$j++) {
	$amp[$j]=$tsysv{$detect}[$j];
	$tim[$j]=$tsyst{$detect}[$j];
    }
    $label=sprintf("$string %s",$detect);
    &vu(\@tim,\@amp,$label);
}	
foreach $detect (sort keys %tsysn1) {
#    print "Detect $detect $tsysn1{$detect}\n";
    $#amp=-1;
    $#tim=-1;
    for($j=0;$j<$tsysn1{$detect};$j++) {
	$amp[$j]=$tsysv1{$detect}[$j];
	$tim[$j]=$tsyst1{$detect}[$j];
    }
    $label=sprintf("Tsys1 %s",$detect);
    &vu(\@tim,\@amp,$label);
}	
foreach $detect (sort keys %tsysn2) {
#    print "Detect $detect $tsysn2{$detect}\n";
    $#amp=-1;
    $#tim=-1;
    for($j=0;$j<$tsysn2{$detect};$j++) {
	$amp[$j]=$tsysv2{$detect}[$j];
	$tim[$j]=$tsyst2{$detect}[$j];
    }
    $label=sprintf("Tsys2 %s",$detect);
    &vu(\@tim,\@amp,$label);
}	
foreach $detect (sort keys %tsysn3) {
#    print "Detect $detect $tsysn3{$detect}\n";
    $#amp=-1;
    $#tim=-1;
    for($j=0;$j<$tsysn3{$detect};$j++) {
	$amp[$j]=$tsysv3{$detect}[$j];
	$tim[$j]=$tsyst3{$detect}[$j];
    }
    $label=sprintf("Tsys3 %s",$detect);
    &vu(\@tim,\@amp,$label);
}	
foreach $chan (sort keys %rxcount) {
    $#amp=-1;
    $#tim=-1;
    for($j=0;$j<$rxcount{$chan};$j++) {
	$amp[$j]=$rx{$chan}[$j];
	$tim[$j]=$rxtime{$chan}[$j];
    }
    $units="";
    $units=" ($rxunits{$chan})" if $rxunits{$chan};
    $label="$rxcmd $chan$units";
#    print "$chan\n";
    &vu(\@tim,\@amp,$label);
}	
	
goto END_EXTRAS;

EXTRAS:
if(defined($opt_1)) {
    for($i=1;$i<15;$i++) {
	if(defined($pcaln[1][$i])) {
	    for ($j=$i+1;$j<15;$j++) {
		if(defined($pcaln[1][$j])) {
		    $done[$i][$j]=1;
		    &phs($i,$j);
		}
	    }
	}
    }
}
if(defined($opt_a)) {
    for($i=1;$i<15;$i+=2) {
	if(defined($pcaln[1][$i])) {
	    for ($j=$i+2;$j<15;$j+=2) {
		if(defined($pcaln[1][$j]) && !$done[$i][$j]) {
		    $done[$i][$j]=1;
		    &phs($i,$j);
		}
	    }
	}
    }
    for($i=2;$i<15;$i+=2) {
	if(defined($pcaln[1][$i])) {
	    for ($j=$i+2;$j<15;$j+=2) {
		if(defined($pcaln[1][$j]) && !$done[$i][$j]) {
		    $done[$i][$j]=1;
		    &phs($i,$j);
		}
	    }
	}
    }
}
if(defined($opt_n)) {
    for($i=1;$i<9;$i++) {
	if(defined($pcaln[1][$i])) {
	    for ($j=$i+1;$j<9;$j++) {
		if(defined($pcaln[1][$j]) && !$done[$i][$j]) {
		    $done[$i][$j]=1;
		    &phs($i,$j);
		}
	    }
	}
    }
    for($i=9;$i<15;$i++) {
	if(defined($pcaln[1][$i])) {
	    for ($j=$i+1;$j<15;$j++) {
		if(defined($pcaln[1][$j]) && !$done[$i][$j]) {
		    $done[$i][$j]=1;
		    &phs($i,$j);
		}
	    }
	}
    }
}
if(defined($opt_w)) {
    for($i=1;$i<5;$i++) {
	if(defined($pcaln[1][$i])) {
	    for ($j=$i+1;$j<5;$j++) {
		if(defined($pcaln[1][$j]) && !$done[$i][$j]) {
		    $done[$i][$j]=1;
		    &phs($i,$j);
		}
	    }
	}
    }
    for($i=5;$i<9;$i++) {
	if(defined($pcaln[1][$i])) {
	    for ($j=$i+1;$j<9;$j++) {
		if(defined($pcaln[1][$j]) && !$done[$i][$j]) {
		    $done[$i][$j]=1;
		    &phs($i,$j);
		}
	    }
	}
    }
    for($i=9;$i<15;$i++) {
	if(defined($pcaln[1][$i])) {
	    for ($j=$i+1;$j<15;$j++) {
		if(defined($pcaln[1][$j]) && !$done[$i][$j]) {
		    $done[$i][$j]=1;
		    &phs($i,$j);
		}
	    }
	}
    }
}

END_EXTRAS:
    $something=0;
    $exit_code=0;

if(!$first) {
    pgtbox("BCTNZYH",0.0,0,"",0.0,0); 
    pglabel("Time","","");
    $something=1;
} elsif($page==1 && !defined($opt_p)){
    pgpanl(1,1);
    pgvport(0.15,.95,0,1);
    pgwindow(-0.5,16.5,0,39);
    pgtext(4,10,"$location Log Plots -- $refdate $save_file Page $page");
    pgtext(6,0,"NOTHING FOUND TO PLOT");
    $exit_code=-2;
}

if(defined($opt_p)) {
    $first = 1;
    for($i=1;$i<17;$i++) {
	if(defined($pcaln[1][$i])) {
	    $#amp=-1;
	    $#tim=-1;
	    $#phs=-1;
	    for($j=0;$j<$pcaln[1][$i];$j++) {
		$amp[$j]=$pcala[1][$i][$j];
		$tim[$j]=$pcalt[1][$i][$j];
		$phs[$j]=$pcalp[1][$i][$j];
	    }
#
# fix up to use dual sideband tsys for normalization if specific sideband data
# doesn't exist
#
	    $chan=$pcall[1][$i];
	    if(!defined($opt_b)) {
		substr($chan,-1)="d";
		$chan=$pcall[1][$i] if !defined($tsysn{$chan});
	    }

	    if(!defined($opt_j)) {		    
		if($first == 1 && $panel !=0) {
		    pgask(-1);
		    pgpanl(1,8);
		    pgpage();
		    $panel=0;
		}
		$label=sprintf("$pcalf[1][$i] Hz Amp $pcall[1][$i]");
		&vup(\@phs,\@amp,$label);
	    } elsif (defined($tsysn{$chan})) {
		($ptref,$pvref)= &nrml($i, $chan);
		$#tima=-1;
		$#vala=-1;
		for($j=0;$j<=$#$ptref;$j++) {
		    $tima[$j]=$$ptref[$j];
		    $vala[$j]=$$pvref[$j];
		}
		($ptref,$pvref,$atref,$avref)=&match(\@tim,\@phs,\@tima,\@vala);
		$label=sprintf("$pcalf[1][$i] Hz Amp(Ts) $pcall[1][$i]");
		&vup($pvref,$avref,$label);
	    }
	}
    }

    if(!$first) {
	pgtbox("BCTN",45.0,0,"",0.0,0); 
	pglabel("Phase","","");
    } elsif($page==1 && !$something) {
	pgpanl(1,1);
	pgvport(0.15,.95,0,1);
	pgwindow(-0.5,16.5,0,39);
	pgtext(4,10,"$location Log Plots -- $refdate $save_file Page $page");
	pgtext(6,0,"NOTHING FOUND TO PLOT");
        $exit_code=-2;
    }
}

pgpanl(1,8);
pgvport(0.15,.95,0,1);
pgwindow(-0.5,16.5,0,39);
pgtext(7.25,15,"Last Page");

pgend();
exit $exit_code;
